package com.cbs.android.component.storage.qiniu;

import com.cbs.android.component.applicationutils.Global;
import com.cbs.android.component.network.HttpClient;
import com.cbs.android.component.network.Request;
import com.cbs.android.component.network.Response;
import com.cbs.android.component.network.ResponseHandler;
import com.cbs.android.component.network.decoder.GsonDecoder;
import com.cbs.android.component.storage.qiniu.entity.Uptoken;
import com.cbs.component.android.storage.storageinterface.StorageHandler;
import com.qiniu.android.http.ResponseInfo;
import com.qiniu.android.storage.Configuration;
import com.qiniu.android.storage.UpCancellationSignal;
import com.qiniu.android.storage.UpCompletionHandler;
import com.qiniu.android.storage.UpProgressHandler;
import com.qiniu.android.storage.UploadManager;
import com.qiniu.android.storage.UploadOptions;

import org.json.JSONObject;

import java.net.HttpURLConnection;
import java.util.Hashtable;

/**
 * Created by broche on 4/5/16.
 */
public class Uploader {
    private static final String TokenUrlTpl = "%s/qiniustorage/api/v1/uptoken?module=%s&operation=%s&%s";
    private UploadManager uploadManager;
    private HttpClient httpClient = Global.getHttpClient().clone();
    private boolean debug = false;
    private boolean isUploading = true;
    private String id;
    private StorageHandler handler;
    private String key;
    private byte[] data;

    public Uploader() {
        Configuration config = new Configuration.Builder()
                .connectTimeout(10) // 链接超时。默认 10秒
                .responseTimeout(60) // 服务器响应超时。默认 60秒
                .zone(com.qiniu.android.common.Zone.zone0) // 设置区域，指定不同区域的上传域名、备用域名、备用IP。默认 Zone.zone0
                .build();
// 重用 uploadManager。一般地，只需要创建一个 uploadManager 对象
        uploadManager = new UploadManager(config);
    }

    public void upload(String id, String key, String module, String operation, Hashtable<String, String> params, byte[] data, StorageHandler handler) {
        StringBuilder sb = new StringBuilder();
        if (params != null && params.size() > 0) {
            for (String pk : params.keySet()) {
                sb.append(pk).append("=").append(params.get(pk));
                sb.append("&");
            }
        }
        String url = String.format(TokenUrlTpl, Global.getServerHost(), module, operation, sb.toString());
        this.id = id;
        this.handler = handler;
        this.key = key;
        this.data = data;
        if (uploadManager != null) {
            Request request = new Request(url)
                    .setTag(id)
                    .setDecoder(new GsonDecoder(Uptoken.class))
                    .setResponseHandler(new ResponseHandler() {
                        @Override
                        public void onResponse(Response response) {
                            if (response.getCode() == HttpURLConnection.HTTP_OK) {
                                Uptoken token = ((Uptoken) response.getResult());
                                uploadManager.put(Uploader.this.data, Uploader.this.key, token.getUptoken(), new UpCompletionHandler() {
                                    @Override
                                    public void complete(String key, ResponseInfo responseInfo, JSONObject result) {
                                        if (responseInfo.isOK()) {
                                            if (Uploader.this.handler != null) {
                                                Uploader.this.handler.onSuccess(Uploader.this.id, key, result.toString());
                                            }
                                        } else {
                                            if (Uploader.this.handler != null) {
                                                Uploader.this.handler.onException(Uploader.this.id, key, new Exception(responseInfo.error));
                                            }
                                        }
                                    }
                                }, new UploadOptions(null, null, false, new UpProgressHandler() {
                                    @Override
                                    public void progress(String key, double percent) {
                                        if (Uploader.this.handler != null) {
                                            Uploader.this.handler.onProgress(Uploader.this.id, key, percent);
                                        }
                                    }
                                }, new UpCancellationSignal() {
                                    @Override
                                    public boolean isCancelled() {
                                        return !isUploading;
                                    }
                                }));
                            } else {
                                if (Uploader.this.handler != null) {
                                    Uploader.this.handler.onException(Uploader.this.id, Uploader.this.key, new Exception(String.format("code: %d\tmessage: %s", response.getCode(), response.getMessage())));
                                }
                            }
                        }

                        @Override
                        public void onException(Request request, Exception e) {
                            if (Uploader.this.handler != null) {
                                Uploader.this.handler.onException(Uploader.this.id, Uploader.this.key, e);
                            }
                        }
                    });
            httpClient.setDebug(debug);
            httpClient.send(request);
        } else {
            if (handler != null) {
                handler.onException(id, key, new Exception("qiniu service is not inited"));
            }
        }
    }

    public void cancel() {
        if (isUploading) {
            httpClient.getOkHttpClient().dispatcher().cancelAll();
            isUploading = false;
            if (handler != null) {
                handler.onException(id, key, new Exception("user canceled"));
            }
        }
    }

    public void setDebug(boolean debug) {
        this.debug = debug;
        httpClient.setDebug(debug);
    }
}
